﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using SharpShare.Collections;
using SharpShare.Storage;

namespace SharpShare {
    public abstract class ShareService : IShareService {
        private string _name;
        private ConcurrentHashSet<IShareSession> _sessions = new ConcurrentHashSet<IShareSession>();
        private List<IStorageProvider> _shares = new List<IStorageProvider>();

        protected ShareService(string name = null) {
            this.State = ShareServiceState.Stopped;
            _name = name;
        }

        #region IShareServer Members

        public event EventHandler<ShareSessionEventArgs> SessionCreated = delegate { };
        public event EventHandler<ShareSessionEventArgs> SessionEnded = delegate { };

        public void Start() {
            ExpectState(ShareServiceState.Stopped);

            this.State = ShareServiceState.Starting;

            try {
                this.StartCore();
                this.State = ShareServiceState.Running;
            } catch {
                this.State = ShareServiceState.Stopped;
                throw;
            }
        }

        public void Stop() {
            ExpectState(ShareServiceState.Running);

            this.State = ShareServiceState.ShuttingDown;

            try {
                this.StopCore();

                this.State = ShareServiceState.Stopped;
            } catch {
                this.State = ShareServiceState.Running;
                throw;
            }
        }

        public ShareServiceState State {
            get;
            protected set;
        }

        public virtual string Name { get { return _name; } }

        public ReadOnlyCollection<IStorageProvider> Shares {
            get {
                return _shares.AsReadOnly();
            }
        }

        public void AddShare(IStorageProvider share) {
            this.OnShareAdding(share);
            _shares.Add(share);
            this.OnShareAdded(share);
        }

        public void RemoveShare(IStorageProvider share) {
            if (_shares.Remove(share)) {
                this.OnShareRemoved(share);
            }
        }

        public ReadOnlyCollection<IShareSession> Sessions {
            get { return _sessions.ToList().AsReadOnly(); }
        }

        #endregion

        protected abstract void StartCore();

        protected abstract void StopCore();

        protected virtual void OnShareAdding(IStorageProvider share) {

        }
        protected virtual void OnShareAdded(IStorageProvider share) {

        }
        protected virtual void OnShareRemoved(IStorageProvider share) {

        }

        protected virtual void OnSessionCreated(IShareSession session) {
            _sessions.Add(session);
            try {
                SessionCreated(this, new ShareSessionEventArgs(session));
            } catch { }
        }
        protected virtual void OnSessionEnded(IShareSession session) {
            _sessions.Remove(session);
            try {
                SessionEnded(this, new ShareSessionEventArgs(session));
            } catch { }
        }

        private void ExpectState(params ShareServiceState[] expectStates) {
            if (Array.IndexOf(expectStates, this.State) == -1) {
                throw new InvalidOperationException("Operation not valid in this state.");
            }
        }

    }


}
